test

10.5 交互式追踪内存泄漏

Memleak还可以用来验证应用程序中的内存管理是否运转正常,例如"从联系人列表中移除了所有Contact对象后,系统中已经就不存在Contact对象了"。Memleak可以交互式运行,在查找内存泄漏时非常有用,对于交互式应用程序来说更是如此,免除了将堆转储到本地文件的麻烦。只要小心仔细些,在辅以相应的系统知识,排查内存泄漏问题就会轻松愉快些了。

假设现在有一个地址簿应用程序,主类是AddressBook,其中包含了几个内部类,例如用于表示联系人的AddressBook$Contact类。可以对地址簿执行添加/删除联系人的操作。现在,来验证一下该应用程序中AddressBook$Contact类的实例是否存在内存泄漏。

正常情况下,Memleak只会显示那些堆内存使用率达到0.1%以上的类型,和创建实例过多的类型。对于那些不会引发内存泄漏的类型,不必太关心,随着应用程序的不断运行,有问题的类会占用越来越多的堆内存。但是,很多时候,被泄漏的内存只会占用一小部分内存,等到应用程序运行了相当一段时间后,才会变得明显起来。为了更好的检测内存泄漏,可以将内存占用率阈值设为0,如下图所示:

Figure 10-15

然后过滤出那些想要测试的类,观察其在应用程序中的行为变化。

第7章中曾经介绍过,JRockit Mission Control中的过滤框可以通过添加regexp前缀来输入正则表达式。

在下面的截图中可以看到,从AddressBook中移除了3个地址,但Contact实例的数量却没有发生变化:

Figure 10-16

移除对象后,AddressBook$Contact实例的数量却没有变化,说明确实发生了内存泄漏。

若希望Memleak能及时显示出堆内存的变化,可以将趋势表的刷新间隔调低。

由于所有的Contact实例都没有被回收掉,因此追踪其中任意一个就可以了。在趋势表中,右键单击Contact类型,选择 List菜单,将任意实例添加到 Instance Graph,展开其引用路径,然后就可以看到一个名为numberToContactMap实例中。该应用程序的开发人员应该熟悉这种数据结构,找出在哪里使用了它,然后解决之就行了。

Figure 10-17

内存泄漏的交互式测试主要包括以下几点:

  1. 建立一个假设,例如"关闭Eclipse PHP Editor后,则编辑器实例以及与其关联的实例都应该被回收掉了";
  2. 在趋势表中过滤出目标类型;
  3. 观察其在应用程序中的行为变化;
  4. 如果发生了内存泄漏,则可以通过对象的引用路径来定位内存泄漏的源头。